#用户接口

from fastapi import Path,HTTPException,Query,APIRouter,Depends,status,Header
from pydantic import BaseModel,Field
from sqlalchemy.sql.functions import user
from sql.db import yhb_crud
from typing import List
from datetime import datetime,timedelta
from fastapi.security import OAuth2PasswordBearer,OAuth2PasswordRequestForm
from passlib.context import CryptContext    #处理哈希密码
from jose import JWTError,jwt               #处理jwt token
from utils.response_code import resp_200,resp_400
from starlette.types import Message


SECRET_KEY = 'test' #hash钥匙
ALGORITHM = 'HS256' #加密算法
ACCESS_TOKEN_EXPIRE_DAYS =  7  #token过期时间
#处理密码
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
#指定获取token的接口
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/childeren/user/token")

user_router = APIRouter()

#定义  用户  数据模型
class UserIn(BaseModel):
    yhbh:str = Field(None)
    yhxm:str = Field(None)
    yhmm:str = Field(None)
    yhzt:str = Field(None)
    czqx:str = Field(None)
    qsph:str = Field(None)
    zzph:str = Field(None)
    bfqs:str = Field(None)
    bfzz:str = Field(None)
    yhgs:str = Field(None)
    yhgroup:str = Field(None)

class TokenIn(BaseModel):
    yhbh:str = Field(None)
    yhmm:str = Field(None)

#修改密码，请求模型
class EditPswdIn(BaseModel):
    old_pswd:str = Query(...,min_length=6,max_length=20)
    new_pswd:str = Query(...,min_length=6,max_length=20)

class UserOut(BaseModel):
    yhbh:str
    yhxm:str
    yhzt:str
    czqx:str
    qsph:str=None
    zzph:str=None
    bfqs:str=None
    bfzz:str=None
    yhgs:str
    yhgroup:str

class Token(BaseModel):
    access_token:str
    token_type:str


 
#校验
def validateUser(id,password):
    user = yhb_crud.get_user(id)
    if not user:    #没有有找到user
        return None
    #验证密码
    if pwd_context.verify(password,user['yhmm']):  
        return user  #返回用户信息
    else:
        return None

#生成token
@user_router.post('/token',response_model=Token)
def token(userinfo:TokenIn):
    #进行用户名密码校验
    res = validateUser(int(userinfo.yhbh),userinfo.yhmm)
    if res == None:
        #失败响应，传递失败消息
        return resp_400(msg='用户名或密码错误')
    pay_load = {'yhbh':res['yhbh'],'yhxm':res['yhxm'],'czqx':res['czqx'],'yhgs':res['yhgs'],'yhgroup':res['yhgroup']}
    # 设置token过期时间
    # pay_load里设置pay_load['exp'] = datetime.utcnow()+timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    
    pay_load['exp'] = datetime.utcnow()+timedelta(days = ACCESS_TOKEN_EXPIRE_DAYS)  #设置过期天数
    access_token = jwt.encode(pay_load,key = SECRET_KEY,algorithm=ALGORITHM) #生成Access token
    #成功，返回resp_200,传递data参数
    return resp_200(data={'access_token':access_token,'token_type':'bearer'})

#校验token，Authorization值
def validToken(Authorization:str = Header(...)):
    try:
        token = Authorization.split(' ')[1]
        pay_load = jwt.decode(token,SECRET_KEY,algorithms=ALGORITHM)
        return pay_load
    except:
        return None


#查询用户信息，需要token
@user_router.get("/user_info")
def read_user(pay_load=Depends(validToken)):
    if not pay_load:
        return resp_400(msg='token校验失败')
    db_user = yhb_crud.get_user(yhbh=pay_load['yhbh'])
    if not db_user:
        return resp_400(msg='用户不存在')
    #成功响应，data内容：UserOut模型，使用数据库查询的用户字典格式，进行实例化
    #最后获取对象的属性字典，赋值给data
    resp_data = UserOut(**db_user).__dict__
    resp_data.update({'avatar':'icons/avatar.jpg'})    #增加头像路径属性，默认为avator.jpg
    return resp_200(data=resp_data)

#查询用户列表
@user_router.post("/user_list", response_model=List[UserOut])
def user_list(params : UserIn):
    #exclude_unset未传递的值会被忽略
    db_user = yhb_crud.get_user_list(params.dict(exclude_unset=True))
    if not db_user:
        raise HTTPException(status_code=404, detail="Not found")
    return db_user


#修改用户密码，需要原密码、新密码、token
@user_router.post("/edit_pswd")
async def edit_pswd(pswd:EditPswdIn,pay_load=Depends(validToken)):
    if not pay_load:
        return resp_400(msg='token校验失败')
    user = validateUser(pay_load['yhbh'],pswd.old_pswd) #验证原密码
    if not user:
        return resp_400(msg='原密码错误！')
    new_hashed_pswd = pwd_context.hash(pswd.new_pswd)    #生成新密码
    yhb_crud.update_user(pay_load['yhbh'],{'yhmm':new_hashed_pswd}) #更新用户
    return resp_200(data={})    #成功响应


#通过用户编号设置用户信息
@user_router.post("/update_user")
def update_user(userInfo : UserIn):
    if userInfo.yhmm:   
        userInfo.yhmm = pwd_context.hash(userInfo.yhmm)
    res = yhb_crud.update_user(userInfo.yhbh,userInfo.dict(exclude_unset=True)) #转化为dict类型
    return {'updated':res}

#通过用户编号删除用户信息
@user_router.post("/delete_user")
def delete_user(yhbh :str = Query(...)):
    res = yhb_crud.delete_user(yhbh) 
    return {'deleted':res}
    

@user_router.post("/add_user")
def add_user(user:UserIn):
    #对密码加密，hash处理
    user.yhmm = pwd_context.hash(user.yhmm)
    res = yhb_crud.add_user(user.dict())
    return {"result":"插入数据成功"}
